package com.zcsy.manage.web.pay;

import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.HttpEntity;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.zcsy.commons.constants.Constants;
import com.zcsy.commons.model.RequestConstants;
import com.zcsy.commons.model.RequestJson;
import com.zcsy.commons.pay.ali.config.AlipayConfig;
import com.zcsy.commons.pay.ali.util.AlipayNotify;
import com.zcsy.commons.pay.ali.util.AlipaySubmit;
import com.zcsy.commons.unique.UniqueNumberUtils;
import com.zcsy.commons.util.PropertiesUtil;
import com.zcsy.manage.model.mall.OrderInfo;
import com.zcsy.manage.model.pay.alipay.AliPayResult;
import com.zcsy.manage.model.pay.weixin.PayOrderRequest;
import com.zcsy.manage.model.pay.weixin.PayOrderResultRequest;
import com.zcsy.manage.model.pay.weixin.PayOrderResultResponse;
import com.zcsy.manage.model.property.CarBillDetail;
import com.zcsy.manage.model.property.FeeBillDetail;
import com.zcsy.manage.persistence.weixin.StringUtil;
import com.zcsy.manage.service.mall.IOrderInfoService;
import com.zcsy.manage.service.property.ICarBillDetailService;
import com.zcsy.manage.service.property.IFeeBillDetailService;
import com.zcsy.manage.web.pay.vo.PayInfoVo;
import com.zcsy.manage.web.tools.WXPayUtils;
/**
 * 订单支付类
 * @Title: PayController.java
 * @Package： com.zcsy.manage.web.pay 
 * @author hubing
 * @Copyright: 2016 武汉恒数利通软件有限公司 All rights reserved.
 * @date 2016年8月24日
 * @version 1.0
 * @see JDK1.7.0_75
 * @since
 */
@Controller
@RequestMapping(value = "pay")
public class PayController {
    
    private Logger logger = Logger.getLogger(PayController.class);
    
    @Autowired
    private IOrderInfoService orderInfoService;
    
    @Autowired
    private IFeeBillDetailService feeBillDetailService;
    
    @Autowired
    private ICarBillDetailService carBillDetailService;
    
    
    /*********************************** Ali pay ******************************************/
    /**
     * 请求支付
     * @Method: aliPay
     * @param outTradeNo 订单编号
     * @param type 订单类别
     *          1：商城订单
     *          2：物业费
     *          3：停车费
     * @date 2016年8月24日
     */
    @RequestMapping("aliPay")
    public ResponseEntity<HttpEntity> aliPay(Model model, String outTradeNo, Integer type) {
        
        // 付款金额，必填
        String total_fee = "";
        switch (type) {
            case Constants.ORDER_TYPE_MALL:
                OrderInfo orderInfo = orderInfoService.selectByOrderNumber(outTradeNo);
                if(!(Constants.ORDER_UNPAID == orderInfo.getState())) {
                    return null;
                }
                total_fee = orderInfo.getFinalPrice().toString();
                break;
            case Constants.ORDER_TYPE_PROPERTY:
                
                FeeBillDetail detail = feeBillDetailService.selectByPrimaryKey(outTradeNo);
                if(detail.getState().intValue() == Constants.AFTER_STATE
                        || detail.getState().intValue() == Constants.BEFORE_STATE){
                    total_fee = detail.getMoney().toString();
                } else {
                    return null;
                }
                break;
            case Constants.ORDER_TYPE_CAR:
                break;
            default:
                break;
        }
        
        
        // 商户订单号，商户网站订单系统中唯一订单号，必填
        String out_trade_no = outTradeNo;
        // 订单名称，必填
        String subject = "订单：" + outTradeNo;
        // 商品描述，可空
        String body = "";

        // 把请求参数打包成数组
        if(PropertiesUtil.isCeshi()) {
            total_fee = "0.01";
        }
        
        Map<String, String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("service", AlipayConfig.service);
        sParaTemp.put("partner", AlipayConfig.partner);
        sParaTemp.put("seller_id", AlipayConfig.seller_id);
        sParaTemp.put("_input_charset", AlipayConfig.input_charset);
        sParaTemp.put("payment_type", AlipayConfig.payment_type);
        sParaTemp.put("notify_url", PropertiesUtil.getPropertiesUtilValues(PropertiesUtil.WEB_PAY_NOTIFY_URL));
        sParaTemp.put("return_url", PropertiesUtil.getPropertiesUtilValues(PropertiesUtil.WEB_PAY_RETURN_URL));
        sParaTemp.put("anti_phishing_key", "");
        sParaTemp.put("exter_invoke_ip", "");
        sParaTemp.put("out_trade_no", out_trade_no);
        sParaTemp.put("subject", subject);
        sParaTemp.put("total_fee", total_fee);
        sParaTemp.put("body", body);
        
        // 如sParaTemp.put("参数名","参数值");
        
        sParaTemp.put("extra_common_param", String.valueOf(type));
        // 建立请求
        String sHtmlText = AlipaySubmit.buildRequest(sParaTemp, "get", "确认");
        model.addAttribute("sHtmlText", sHtmlText);

        return new ResponseEntity(model, HttpStatus.OK);
    }
    
    /**
     * 支付完成之后异步通知服务器
     * @Method: aliNotify
     * @author hubing
     * @date 2016年8月24日
     */
    @RequestMapping("aliNotify")
    public String aliNotify(HttpServletRequest request){
        
        //获取支付宝POST过来反馈信息
        Map<String,String> params = new HashMap<String,String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
            params.put(name, valueStr);
        }
        
        //获取支付宝的通知返回参数
        //商户订单号
        String out_trade_no = request.getParameter("out_trade_no");

        //支付宝交易号
        String trade_no = request.getParameter("trade_no");

        //交易状态
        String trade_status = request.getParameter("trade_status");

        // 订单类别
        String orderType = request.getParameter("extra_common_param");
        
        logger.info("aliNotify called out_trade_no:[" + out_trade_no + "] orderType:[" + orderType + "]");
        
        if(AlipayNotify.verify(params)){//验证成功
            boolean flg = false;
            try {
                if(trade_status.equals("TRADE_FINISHED")){
                    
                } else if (trade_status.equals("TRADE_SUCCESS")){
                    AliPayResult aliResult = new AliPayResult();
                    
                    aliResult.setPaySystem(Constants.PAY_SYSTEM_WEB);
                    aliResult.setExternal_trade_no(out_trade_no);
                    aliResult.setExternal_resp_code(trade_status);
                    aliResult.setTotal_fee(new BigDecimal(request.getParameter("total_fee")));
                    
                    orderInfoService.payOrder(out_trade_no, aliResult);
                    
                    flg = true;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if(flg){
                return "success";
            }else{
                return "fail";
            }
        } else {//验证失败
            return "fail";
        }
    }
    
    /**
     * 支付宝支付完成之后同步调用接口
     * @Method: aplReturnUrl
     * @author hubing
     * @date 2016年8月24日
     */
    @RequestMapping("aliReturnUrl")
    public String aliReturnUrl(HttpServletRequest request){
        //获取支付宝GET过来反馈信息
        Map<String,String> params = new HashMap<String,String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        
        //商户订单号
        String out_trade_no = request.getParameter("out_trade_no");

        //交易状态
        String trade_status = request.getParameter("trade_status");
        
        // 订单类别
        String orderType = request.getParameter("extra_common_param");

        //计算得出通知验证结果
        boolean verify_result = AlipayNotify.verify(params);
        
        String returnUrl = "";
        if(verify_result){//验证成功
            if(trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")){
                AliPayResult aliResult = new AliPayResult();
                
                aliResult.setPaySystem(Constants.PAY_SYSTEM_WEB);
                aliResult.setExternal_trade_no(out_trade_no);
                aliResult.setExternal_resp_code(trade_status);
                aliResult.setTotal_fee(new BigDecimal(request.getParameter("total_fee")));
                
                switch (Integer.parseInt(orderType)) {
                    case Constants.ORDER_TYPE_MALL:
                        orderInfoService.payOrder(out_trade_no, aliResult);
                        returnUrl = "redirect:/shopcart/shopcartList";
                        break;
                    case Constants.ORDER_TYPE_PROPERTY:
                        feeBillDetailService.payFeeBill(out_trade_no, aliResult);
                        returnUrl = "redirect:/propertyBill/getMyBill";
                        break;
                    case Constants.ORDER_TYPE_CAR:
                        carBillDetailService.payCarBill(out_trade_no, aliResult);
                        returnUrl = "redirect:/carBill/getCarManage?payCarBill=1";
                        break;
                    default:
                        break;
                }
            }
        }
        return returnUrl; 
    }
    
    /*********************************** WeiXin pay ******************************************/
    /**
     * 订单支付界面
     * @Method: toPayBillPage
     * @param type 订单类别
     *          1：商城订单
     *          2：物业费
     *          3：停车费
     * @param billId
     * @author hubing
     */
    @RequestMapping(value = "toPayBillPage", method = RequestMethod.GET)
    public String toPayBillPage(HttpServletRequest request, Model model, Integer type, String billId) {
        PayInfoVo payInfo = new PayInfoVo();
        switch (type) {
            case Constants.ORDER_TYPE_MALL:
                break;
            case Constants.ORDER_TYPE_PROPERTY:
                // 根据房屋id查询账单详情
                FeeBillDetail feeBillDetail = feeBillDetailService.selectByPrimaryKey(billId);
                payInfo.setTradeNo(feeBillDetail.getId());
                payInfo.setTotalFee(feeBillDetail.getMoney());
                break;
            case Constants.ORDER_TYPE_CAR:
                CarBillDetail detail = carBillDetailService.selectByPrimaryKey(billId);
                payInfo.setTradeNo(detail.getId());
                payInfo.setTotalFee(detail.getMoney());
                break;
            default:
                break;
        }
        payInfo.setType(type);
        model.addAttribute("payInfo", payInfo);
        return "common/pay_bill";
    }
    
    /**
     * 生成微信支付二维码
     * @Method: payCode
     * @param orderNumber
     */
    @RequestMapping("payCode")
    public void payCode(String orderNumber, Integer type, HttpServletRequest request, HttpServletResponse response) {
        // 生成订单
        String ip = getIp(request);
        ip = request.getRemoteHost();
        try {
            PayOrderRequest payRequest = new PayOrderRequest();
            payRequest.setNonce_str(UniqueNumberUtils.get16UniqueNumber());
            payRequest.setBody(new String("DLife test pay".getBytes(), "UTF-8"));
            String totlaFee = "1";
            String notifyUrl = "1";
            switch (type) {
                case Constants.ORDER_TYPE_MALL:
                    if(!PropertiesUtil.isCeshi()) {
                        totlaFee = orderInfoService.selectByOrderNumber(orderNumber).getFinalPrice().toString();
                    }
                    break;
                case Constants.ORDER_TYPE_PROPERTY:
                    if(!PropertiesUtil.isCeshi()) {
                        totlaFee = feeBillDetailService.selectByPrimaryKey(orderNumber).getMoney().toString();
                    }
                    break;
                case Constants.ORDER_TYPE_CAR:
                    if(!PropertiesUtil.isCeshi()) {
                        totlaFee = carBillDetailService.selectByPrimaryKey(orderNumber).getMoney().toString();
                    }
                    break;
                default:
                    break;
            }
            
            payRequest.setOut_trade_no(orderNumber);
            payRequest.setTotal_fee(totlaFee);
            payRequest.setSpbill_create_ip(ip);
            payRequest.setNotify_url(notifyUrl);
            
            String orderInfo = WXPayUtils.createWeixinPayRequset(payRequest);
            logger.info("request xml ==== " + orderInfo);
            String codeUrl = WXPayUtils.getSubmitOrderResponse(orderInfo);
            
            int width = 200;
            int height = 200;
            String format = "png";
            Hashtable hints = new Hashtable();
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            BitMatrix bitMatrix = new MultiFormatWriter().encode(codeUrl, BarcodeFormat.QR_CODE, width, height, hints);
            OutputStream out = null;
            out = response.getOutputStream();
            MatrixToImageWriter.writeToStream(bitMatrix, format, out);
            out.flush();
            out.close();
        } catch (Exception e) {
            logger.error(e);
            e.printStackTrace();
        }
    }
    
    @RequestMapping(value="wxPayResult" , method = RequestMethod.GET)
    @ResponseBody
    public RequestJson wxPayResult(String orderNumber, Integer type, HttpServletRequest request,
            HttpServletResponse response) {
        RequestJson result = new RequestJson();
        try {
            PayOrderResultRequest resultReq = new PayOrderResultRequest();
            resultReq.setOut_trade_no(orderNumber);
            String requestXml = WXPayUtils.createWXPayResultRequest(resultReq);
            PayOrderResultResponse payResult = WXPayUtils.getPayResult(requestXml);
            
            // 根据微信文档return_code 和result_code都为SUCCESS的时候才会返回code_url
            if(null != payResult) {
                if("SUCCESS".equals(payResult.getReturn_code()) && "SUCCESS".equals(payResult.getResult_code())){
                    if("SUCCESS".equals(payResult.getTrade_state())){
                        
                        switch (type) {
                            case Constants.ORDER_TYPE_MALL:
                                break;
                            case Constants.ORDER_TYPE_PROPERTY:
                                feeBillDetailService.payFeeBill(orderNumber, payResult);
                                break;
                            case Constants.ORDER_TYPE_CAR:
                                carBillDetailService.payCarBill(orderNumber, payResult);
                                break;
                            default:
                                break;
                        }
                    } else {
                        result.setMsg(payResult.getTrade_state_desc());
                        result.setSuccess(false);
                    }
                } else {
                    result.setMsg(payResult.getErr_code_des()); 
                    result.setSuccess(false);
                }
            } else {
                result.setMsg("请求支付结果失败"); 
                result.setSuccess(false);
            }
        } catch (Exception e) {
            e.printStackTrace();
            result.setMsg(RequestConstants.NET_ERROR);
            result.setSuccess(false);
        }
        return result;
    }
    
    
    public static String getIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if(!StringUtil.isEmptyString(ip) && !"unKnown".equalsIgnoreCase(ip)){
            //多次反向代理后会有多个ip值，第一个ip才是真实ip
            int index = ip.indexOf(",");
            if(index != -1){
                return ip.substring(0,index);
            }else{
                return ip;
            }
        }
        ip = request.getHeader("X-Real-IP");
        if((!StringUtil.isEmptyString(ip)) && !"unKnown".equalsIgnoreCase(ip)){
            return ip;
        }
        return request.getRemoteAddr();
    }
}
